package generic;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;


public class Holder<T>{

	static class Food{}
	
	static class Fruit extends Food{}
	
	static class Apple extends Fruit{}
	
	static class RedApple extends Apple{}
	
	static class Orange extends Fruit{}

	private T value;
	
	public T get(){
		return value;
	}
	public void set(T obj){
		value = obj;
	}
	
 
	
	public Holder(){
		
	}
	
	public Holder(T value){
		this.value = value;
	}

	@Override
	public boolean equals(Object obj){
		return this.value.equals(obj);
	} 
	
	public static void main(String[] args) {
		
		Holder<Apple> appleHolder = new Holder<Apple>(new Apple());
		Apple apple = appleHolder.get();
		
		Holder<? extends Fruit> fruitHolder = new Holder();
//		fruitHolder = appleHolder;
//		Fruit f = fruitHolder.get();
//		apple = (Apple)fruitHolder.get();
		
		System.out.println(fruitHolder.equals(apple));
		// compile error
//		fruitHolder.set(new Apple());
//		fruitHolder.set(new Fruit());
//		fruitHolder.set(new Object());
		
//		Orange c = (Orange)fruitHolder.get();
		
		Holder<? super Fruit> fruitHolder2 = new Holder();
		fruitHolder2.set(new Apple());
		fruitHolder2.set(new Fruit());
		
		List<? extends Fruit> appList2 = new ArrayList<Apple>();
		appList2.add(null);
//		appList2.add(new Fruit());
//		appList2.add(new Apple());
//		appList2.add(new RedApple());
		
//		List<Apple> list33 = new ArrayList<Holder.Apple>();
//		List<? extends Fruit> appList23 = list33;
		
		Fruit item = appList2.get(0);
		Apple item2 = (Apple)appList2.get(0);
		
		List<? super Fruit> appList = new ArrayList<Fruit>();
//		appList.add(new Food());
		appList.add(new Fruit());
		appList.add(new Apple());
		appList.add(new RedApple());
//		Fruit item = appList.get(0);
//		Object item = appList.get(0);
		
		appList.contains(new Fruit());
		appList.contains(new Apple());
		
		List<Fruit> appList3 = new ArrayList<Fruit>();
		appList3.add(new Fruit());
		appList3.add(new Apple());
		appList3.add(new RedApple());
		
		do1(new ArrayList<Fruit>());
//		do1(new ArrayList<Apple>());
//		Holder.<Fruit>do10(new ArrayList<Apple>());
		do2(new ArrayList<Fruit>());
		do2(new ArrayList<Apple>());
		do3(new ArrayList<Fruit>());
//		do3(new ArrayList<Apple>());
		
		f1(new ArrayList<Fruit>(),new Apple());
		f1(new ArrayList<Apple>(),new Apple());
		
		f2(new ArrayList<Fruit>(),new Apple());
		f2(new ArrayList<Apple>(),new Apple());
		
		List<Fruit> fr1 = new ArrayList<Holder.Fruit>();
		List<Apple> fr2 = new ArrayList<Holder.Apple>();
		f1(fr1,new Apple());
		f1(fr1,new Apple());
		f2(fr2,new Apple());
		f2(fr2,new Apple());
		
//		List<Fruit> f11 = Arrays.asList(new Apple(),new RedApple());
		List<Fruit> f22 = Arrays.<Fruit>asList(new Apple(),new RedApple());
		List<Fruit> f33 = null;
		Collections.addAll(f33,new Apple(),new RedApple());
		
		Holder.hello("lhl");
	}
	
	static <P> void hello(P args){
		
	}
	
	static void do1(List<? super Fruit> list){}

	static <E> void do10(List<? super E> list){}

	static void do2(List<? extends Fruit> list){}
	
	static void do3(List<Fruit> list){}
	
	
	static <E> void f1(List<E> list,E item){
		list.add(item);
	}

	static <E> void f2(List<? super E> list,E item){
		list.add(item);
	}
}
